package com.appointmentmanager.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;

import com.appointmentmanager.dao.UserDao;
import com.appointmentmanager.model.User;

public class JdbcUserDao implements UserDao {

//	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private SimpleJdbcTemplate simpleJdbcTemplate;
	private SimpleJdbcInsert insertTemplate;
	private SimpleJdbcInsert insertAuthorityTemplate;

	public void setDataSource(DataSource dataSource) {
		this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
		this.insertTemplate = new SimpleJdbcInsert(dataSource).withTableName(
				"users").usingGeneratedKeyColumns("id");
		this.insertAuthorityTemplate = new SimpleJdbcInsert(dataSource).withTableName(
				"authorities");
	}
	
	public List<User> getUsers() {
		String sql = "select * from users where username in (select username from authorities where authority='ROLE_USER')";
		List<User> users = simpleJdbcTemplate.query(sql,
				new UserMapper());

		return users;
	}

	public User getUserByUserName(String username) {
		String sql = "select * from users where username = ?";
		User user = null;
		
		try {
			user = this.simpleJdbcTemplate.queryForObject(sql, new UserMapper(), username);
		} catch (Exception e) {
//			logger.debug(e.getMessage());
		}
		
		return user;
	}

	public User getUserById(Long id) {
		// TODO Auto-generated method stub
		String sql = "select * from users where id = ?";
		User user = null;
		
		try {
			user = this.simpleJdbcTemplate.queryForObject(sql, new UserMapper(), id);
		} catch (Exception e) {
//			logger.debug(e.getMessage());
		}
		
		return user;
	}

	public boolean insert(User user) {
//		logger.debug("insert new user: " + user);
//		
		Map<String, Object> parameters = new HashMap<String, Object>();
		parameters.put("username", user.getUsername());
		parameters.put("password", user.getPassword());
		parameters.put("enabled", user.getEnabled());
		parameters.put("firstname", user.getFirstName());
		parameters.put("lastname", user.getLastName());
		
		Number id = null;
		try {
			id = insertTemplate.executeAndReturnKey(parameters);
		} catch (Exception e) { // TODO: find the correct exception
//			logger.debug(e.getMessage());
			return false;
		}
		
		if (id != null) {
			user.setId(id.longValue());
			
			parameters = new HashMap<String, Object>();
			parameters.put("username", user.getUsername());
			parameters.put("authority", "ROLE_USER");
			
			this.insertAuthorityTemplate.execute(parameters);
		} else {
			return false;
		}
		
		return true;
	}

	public void update(User User) {
		// TODO Auto-generated method stub
	}

	public void setEnabled(Long id, boolean enabled) {
		
		String sql = "UPDATE users SET enabled=0 where id = ?";
		if (enabled) {
			sql = "UPDATE users SET enabled=1 where id = ?";
		}
		
		simpleJdbcTemplate.update(sql, id);
	}
	
	
	public List<String> getAuthoritiesByUsername(String username) {
		String sql = "select authority from authorities where username = ?";
		List<String> authorities = null;
		
//		logger.debug("execute the get authorities query");
		
		try {
			authorities = this.simpleJdbcTemplate.query(sql,
					new AuthorityMapper(), username);
		} catch (EmptyResultDataAccessException ex) {
//			logger.debug("user " + username + " is not in the database");
		}

		return authorities;
	}
	
	/**
	 * RowMapper for Users objects.
	 */
	private static final class AuthorityMapper implements RowMapper<String> {
		
		public String mapRow(ResultSet rs, int rowNum) throws SQLException {
			String authority = rs.getString("authority");
			return	authority;
		}
	}
	
	/**
	 * RowMapper for Users objects.
	 */
	private static final class UserMapper implements RowMapper<User> {
		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
			User user = new User();
			user.setId(rs.getLong("id"));
			user.setUsername(rs.getString("username"));
			user.setPassword(rs.getString("password"));
			user.setEnabled(rs.getBoolean("enabled"));
			user.setFirstName(rs.getString("firstname"));
			user.setLastName(rs.getString("lastname"));
			return user;
		}
	}
}
